﻿using UnityEngine;
using UnityEngine.EventSystems;
using QFramework;
using System.Collections;

namespace HKTools
{
    /// <summary>
    /// Camera多目标切换管理工具，摄像机控制脚本
    /// </summary>
    [RequireComponent(typeof(Camera)), DisallowMultipleComponent]
    public class HK_TargetCamera : HKTargetCam_BaseController
    {
        IHK_TargetCamSystem targetCamSystem;

        [Header("初始化目标：")]
        public HK_TargetEnum initTarget;

        [field: SerializeField, Header("移动速度：")] float MoveSpeed { get; set; }
        [field: SerializeField, Header("缩放速度：")] float ZoomSpeed { get; set; }

        [field: SerializeField, Header("最大俯仰角"), Range(0, 89)] float MaxAngle { get; set; }
        [field: SerializeField, Header("最小俯仰角"), Range(0, 89)] float MinAngle { get; set; }

        // 当前的 RotTarget 目标
        HK_RotTarget CurRotTarget { get; set; }

        // 当前 FollowTarget 目标
        HK_FollowTarget CurFollowTarget { get; set; }

        // 当前 AreaTarget 目标
        HK_AreaTarget CurAreaTarget { get; set; }

        // 当前 BirdViewTarget 目标 
        HK_BirdViewTarget CurBirdViewTarget { get; set; }

        // 当前 摄像机
        Camera CurCamera { get; set; }

        Vector2 xLimitPos, zLimitPos;

        bool isAreaCamForward;

        bool isOrthographic;

        Vector2 moveTargetValue;

        float zoomTargetValue;

        Vector3 lastFollowTargetPos;

        void Awake()
        {
            // 获取 IHK_TargetCamSystem 系统层
            targetCamSystem = this.GetSystem<IHK_TargetCamSystem>();

            // 初始化 被控制的 Camera
            targetCamSystem.InitCamera(this);

            CurCamera = GetComponent<Camera>();
        }

        void Start()
        {
            // 如果初始化的目标不是“无”，则发送命令，切换目标
            if (initTarget != HK_TargetEnum.None)
            {
                this.SendCommand(new CMD_ChangeCamTarget(initTarget));
            }
        }

        void LateUpdate()
        {
            if (targetCamSystem.IsFreezeCam || targetCamSystem.IsChangingTarget || targetCamSystem.CurTarget == null)
                return;

            switch (targetCamSystem.CurTarget.TargetKind)
            {
                case HK_TargetKind.RotTarget:
                    MoveCtrl_RotTarget();
                    ZoomCtrl_RotTarget();
                    break;
                case HK_TargetKind.AreaTarget:
                    MoveCtrl_AreaTarget();
                    ZoomCtrl_AreaTarget();
                    break;
                case HK_TargetKind.FollowTarget:
                    MoveCtrl_FollowTarget();
                    ZoomCtrl_FollowTarget();
                    break;
                case HK_TargetKind.BirdViewTarget:
                    MoveCtrl_BirdViewTarget();
                    ZoomCtrl_BirdViewTarget();
                    break;
            }
        }

        /// <summary>
        /// 设置相机的 移动速度、缩放速度
        /// </summary>
        public void SetMoveAndZoomSpeed(float moveSpeed, float zoomSpeed)
        {
            MoveSpeed = moveSpeed;
            ZoomSpeed = zoomSpeed;
        }

        /// <summary>
        /// 设置相机的 最大俯仰角、最小俯仰角
        /// </summary>
        public void SetPitchAngle(float minAngle, float maxAngle)
        {
            MinAngle = minAngle;
            MaxAngle = maxAngle;
        }

        /// <summary>
        /// 当切换到 RotTarget 时
        /// </summary>
        public void OnSwitchToRotTarget(HK_RotTarget rotTarget)
        {
            if (isOrthographic)
            {
                isOrthographic = false;
                StartCoroutine(IE_ChangeProjection());
            }

            moveTargetValue = Vector2.zero;
            zoomTargetValue = 0;

            CurRotTarget = rotTarget;
        }

        /// <summary>
        /// 当切换到 AreaTarget 时
        /// </summary>
        public void OnSwitchToAreaTarget(HK_AreaTarget areaTarget)
        {
            if (isOrthographic)
            {
                isOrthographic = false;
                StartCoroutine(IE_ChangeProjection());
            }

            if (Vector3.Dot(areaTarget.transform.forward, Vector3.forward) > 0)
            {
                isAreaCamForward = false;
            }
            else
            {
                isAreaCamForward = true;
            }

            xLimitPos = new Vector2(areaTarget.TargetPos.x - areaTarget.areaWidth / 2, areaTarget.TargetPos.x + areaTarget.areaWidth / 2);

            zLimitPos = new Vector2(areaTarget.TargetPos.z - areaTarget.areaLength / 2, areaTarget.TargetPos.z + areaTarget.areaLength / 2);

            moveTargetValue = Vector2.zero;
            zoomTargetValue = 0;

            moveTargetValue.x = areaTarget.TargetPos.x;
            moveTargetValue.y = areaTarget.TargetPos.z;

            CurAreaTarget = areaTarget;
        }

        /// <summary>
        /// 当切换到 FollowTarget 时
        /// </summary>
        public void OnSwitchToFollowTarget(HK_FollowTarget followTarget)
        {
            if (isOrthographic)
            {
                isOrthographic = false;
                StartCoroutine(IE_ChangeProjection());
            }

            moveTargetValue = Vector2.zero;
            zoomTargetValue = 0;

            lastFollowTargetPos = followTarget.transform.position;
            CurFollowTarget = followTarget;
        }

        /// <summary>
        /// 当切换到 BirdViewTarget 时
        /// </summary>
        public void OnSwitchToBirdViewTarget(HK_BirdViewTarget birdViewTarget)
        {
            if (!isOrthographic)
            {
                isOrthographic = true;
                StartCoroutine(IE_ChangeProjection());
            }

            CurCamera.orthographicSize = birdViewTarget.OrthographicSize;

            xLimitPos = new Vector2(birdViewTarget.TargetPos.x - birdViewTarget.areaWidth / 2, birdViewTarget.TargetPos.x + birdViewTarget.areaWidth / 2);

            zLimitPos = new Vector2(birdViewTarget.TargetPos.z - birdViewTarget.areaLength / 2, birdViewTarget.TargetPos.z + birdViewTarget.areaLength / 2);

            moveTargetValue.x = birdViewTarget.TargetPos.x;
            moveTargetValue.y = birdViewTarget.TargetPos.z;

            zoomTargetValue = 0;

            CurBirdViewTarget = birdViewTarget;
        }

        // RotTarget时，移动控制
        void MoveCtrl_RotTarget()
        {
            // 获取移动输入
            Vector2 moveInput = GetMoveInput();

            // 根据鼠标左键状态进行插值计算
            float lerpTime = 8f * Time.deltaTime;

            Vector2 velocity = Vector2.zero;

            moveTargetValue.x = Mathf.SmoothDamp(moveTargetValue.x, moveInput.x, ref velocity.x, lerpTime);
            moveTargetValue.y = Mathf.SmoothDamp(moveTargetValue.y, moveInput.y, ref velocity.y, lerpTime);

            /*************************** 限制视角 边界范围 *****************************/

            if (CurRotTarget.leftRotLimit != 0 || CurRotTarget.rightRotLimit != 0)
            {
                Vector3 targetForward = Vector3.ProjectOnPlane(CurRotTarget.transform.forward, Vector3.up);
                Vector3 cameraDirection = Vector3.ProjectOnPlane(transform.position - CurRotTarget.transform.position, Vector3.up);

                float angle = Vector3.Angle(targetForward, cameraDirection);

                float crossY = Vector3.Cross(CurRotTarget.transform.forward, transform.forward).y;
                bool isCamOnRight = crossY < 0;

                if (isCamOnRight && angle > CurRotTarget.rightRotLimit && moveTargetValue.x > 0)
                {
                    moveTargetValue.x = 0;
                }
                else if (!isCamOnRight && angle > CurRotTarget.leftRotLimit && moveTargetValue.x < 0)
                {
                    moveTargetValue.x = 0;
                }
            }

            ApplyCommonRotation(CurRotTarget.transform);
        }

        // RotTarget时，缩放控制
        void ZoomCtrl_RotTarget()
        {
            var zoomValue = GetZoomInput();

            // 如果当前距离小于最小距离，并且滚轮向上滚动，则不执行缩放
            if (Vector3.Distance(transform.position, CurRotTarget.transform.position) < CurRotTarget.minDis && zoomValue > 0)
                zoomValue = 0;

            // 如果当前距离大于最大距离，并且滚轮向下滚动，则不执行缩放
            if (Vector3.Distance(transform.position, CurRotTarget.transform.position) > CurRotTarget.maxDis && zoomValue < 0)
                zoomValue = 0;

            // 使用平滑插值计算缩放目标值
            zoomTargetValue = Mathf.Lerp(zoomTargetValue, zoomValue, 10 * Time.deltaTime);

            if (Mathf.Abs(zoomTargetValue - zoomValue) < 0.001f)
                zoomTargetValue = zoomValue;

            // 如果缩放目标值不为0，则执行缩放操作
            if (zoomTargetValue != 0)
            {
                // 计算新的相机位置
                Vector3 newPosition = transform.position + (Vector3.forward * zoomTargetValue * ZoomSpeed);

                // 计算新位置与目标位置的距离
                float newDistance = Vector3.Distance(newPosition, CurRotTarget.transform.position);

                // 在缩放前，检查新位置是否会导致相机位置超出限制
                if (newDistance <= CurRotTarget.minDis && zoomTargetValue > 0)
                    return;

                if (newDistance >= CurRotTarget.maxDis && zoomTargetValue < 0)
                    return;

                transform.Translate(Vector3.forward * zoomTargetValue * ZoomSpeed);
            }
        }

        // FollowTarget时，移动控制
        void MoveCtrl_FollowTarget()
        {
            var offset = CurFollowTarget.transform.position - lastFollowTargetPos;

            if (offset.magnitude != 0)
            {
                transform.position += offset;
                lastFollowTargetPos = CurFollowTarget.transform.position;
            }

            // 获取移动输入
            Vector2 moveInput = GetMoveInput();

            // 根据鼠标左键状态进行插值计算
            float lerpTime = 8f * Time.deltaTime;

            Vector2 velocity = Vector2.zero;

            moveTargetValue.x = Mathf.SmoothDamp(moveTargetValue.x, moveInput.x, ref velocity.x, lerpTime);
            moveTargetValue.y = Mathf.SmoothDamp(moveTargetValue.y, moveInput.y, ref velocity.y, lerpTime);

            ApplyCommonRotation(CurFollowTarget.transform);
        }

        // FollwTarget时，缩放控制
        void ZoomCtrl_FollowTarget()
        {
            var zoomValue = GetZoomInput();

            // 如果当前距离小于最小距离的105%并且滚轮向上滚动，则不执行缩放
            if (Vector3.Distance(transform.position, CurFollowTarget.transform.position) < CurFollowTarget.minDis && zoomValue > 0)
                zoomValue = 0;

            // 如果当前距离大于最大距离并且滚轮向下滚动，则不执行缩放
            if (Vector3.Distance(transform.position, CurFollowTarget.transform.position) > CurFollowTarget.maxDis && zoomValue < 0)
                zoomValue = 0;

            // 使用平滑插值计算缩放目标值
            zoomTargetValue = Mathf.Lerp(zoomTargetValue, zoomValue, 10 * Time.deltaTime);

            if (Mathf.Abs(zoomTargetValue - zoomValue) < 0.001f)
                zoomTargetValue = zoomValue;

            // 如果缩放目标值不为0，则执行缩放操作
            if (zoomTargetValue != 0)
            {
                // 计算新的相机位置
                Vector3 newPosition = transform.position + (Vector3.forward * zoomTargetValue * ZoomSpeed);

                // 计算新位置与目标位置的距离
                float newDistance = Vector3.Distance(newPosition, CurFollowTarget.transform.position);

                // 在缩放前，检查新位置是否会导致相机位置超出限制
                if (newDistance <= CurFollowTarget.minDis && zoomTargetValue > 0)
                    return;

                if (newDistance >= CurFollowTarget.maxDis && zoomTargetValue < 0)
                    return;

                transform.Translate(Vector3.forward * zoomTargetValue * ZoomSpeed);
            }
        }

        // AreaTarget时，移动控制
        void MoveCtrl_AreaTarget()
        {
            // 获取移动输入
            Vector2 moveInput = GetMoveInput();

            if (isAreaCamForward)
            {
                moveTargetValue.x -= moveInput.x * Time.deltaTime * MoveSpeed * 25;
                moveTargetValue.y -= moveInput.y * Time.deltaTime * MoveSpeed * 25;
            }
            else
            {
                moveTargetValue.x += moveInput.x * Time.deltaTime * MoveSpeed * 25;
                moveTargetValue.y += moveInput.y * Time.deltaTime * MoveSpeed * 25;
            }

            moveTargetValue.x = Mathf.Clamp(moveTargetValue.x, xLimitPos.x, xLimitPos.y);
            moveTargetValue.y = Mathf.Clamp(moveTargetValue.y, zLimitPos.x, zLimitPos.y);

            transform.position = Vector3.Lerp(transform.position, new Vector3(moveTargetValue.x, transform.position.y, moveTargetValue.y), MoveSpeed * Time.deltaTime * 10);
        }

        // AreaTarget时，缩放控制 
        void ZoomCtrl_AreaTarget()
        {
            float zoomValue = GetZoomInput();

            zoomTargetValue = Mathf.Lerp(zoomTargetValue, zoomValue, Time.deltaTime * 10);

            if (CurCamera.fieldOfView > 85 && zoomTargetValue < 0)
                return;

            if (CurCamera.fieldOfView < 35 && zoomTargetValue > 0)
                return;

            CurCamera.fieldOfView -= zoomTargetValue * ZoomSpeed * 2f;
        }

        // BirdViewTarget时，移动控制
        void MoveCtrl_BirdViewTarget()
        {
            // 获取移动输入
            Vector2 moveInput = GetMoveInput();

            moveTargetValue.x += moveInput.x * Time.deltaTime * MoveSpeed * 60;
            moveTargetValue.y += moveInput.y * Time.deltaTime * MoveSpeed * 60;

            moveTargetValue.x = Mathf.Clamp(moveTargetValue.x, xLimitPos.x, xLimitPos.y);
            moveTargetValue.y = Mathf.Clamp(moveTargetValue.y, zLimitPos.x, zLimitPos.y);

            transform.position = Vector3.Lerp(transform.position, new Vector3(moveTargetValue.x, transform.position.y, moveTargetValue.y), Time.deltaTime * MoveSpeed * 10);
        }

        // BirdViewTarget时，缩放控制
        void ZoomCtrl_BirdViewTarget()
        {
            float zoomValue = GetZoomInput();

            zoomTargetValue = Mathf.Lerp(zoomTargetValue, zoomValue, Time.deltaTime * 10);

            if (CurCamera.orthographicSize > 50 && zoomTargetValue < 0)
                return;

            if (CurCamera.orthographicSize < 10 && zoomTargetValue > 0)
                return;

            CurCamera.orthographicSize -= zoomTargetValue * ZoomSpeed;
        }

        // 切换正交、透视摄像机投影方式，时间为0.3s
        IEnumerator IE_ChangeProjection()
        {
            //定义变量存放当前摄像机的透视和正视矩阵信息
            Matrix4x4 fromMatrix, toMatrix;

            float currentT = 0f;

            while (currentT < 0.2f)  // 0.5s后切换正交或透视状态
            {
                yield return null;

                currentT += Time.deltaTime * 0.4f;

                if (CurCamera.orthographic) //如果当前摄像机为正视状态
                {
                    fromMatrix = CurCamera.projectionMatrix;

                    CurCamera.orthographic = false;
                    CurCamera.ResetProjectionMatrix();

                    toMatrix = CurCamera.projectionMatrix;

                    CurCamera.orthographic = true;
                    CurCamera.projectionMatrix = MatrixLerp(fromMatrix, toMatrix, currentT * currentT);
                }
                else //否则当前摄像机为透视状态
                {
                    fromMatrix = CurCamera.projectionMatrix;

                    CurCamera.orthographic = true;
                    CurCamera.ResetProjectionMatrix();

                    toMatrix = CurCamera.projectionMatrix;

                    CurCamera.orthographic = false;
                    CurCamera.projectionMatrix = MatrixLerp(fromMatrix, toMatrix, currentT);
                }
            }

            CurCamera.orthographic = !CurCamera.orthographic;
            CurCamera.ResetProjectionMatrix();
        }

        Matrix4x4 MatrixLerp(Matrix4x4 from, Matrix4x4 to, float t)
        {
            //插值计算时应用的存储变量
            Matrix4x4 tempMatrix = new Matrix4x4();

            t = Mathf.Clamp(t, 0.0f, 1.0f);

            tempMatrix.SetRow(0, Vector4.Lerp(from.GetRow(0), to.GetRow(0), t));
            tempMatrix.SetRow(1, Vector4.Lerp(from.GetRow(1), to.GetRow(1), t));
            tempMatrix.SetRow(2, Vector4.Lerp(from.GetRow(2), to.GetRow(2), t));
            tempMatrix.SetRow(3, Vector4.Lerp(from.GetRow(3), to.GetRow(3), t));
            return tempMatrix;
        }

        /// <summary>
        /// 判断指针是否在 UI 上
        /// </summary>
        bool IsPointerOverUI()
        {
#if UNITY_STANDALONE_WIN || UNITY_EDITOR || UNITY_WEBGL
            return EventSystem.current != null && EventSystem.current.IsPointerOverGameObject();
#elif UNITY_ANDROID
            return EventSystem.current != null &&  Input.touchCount > 0 &&  EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId);
#endif
        }

        /// <summary>
        /// 获取移动输入
        /// </summary>
        Vector2 GetMoveInput()
        {
            if (IsPointerOverUI())
            {
                return Vector2.zero;
            }

#if UNITY_STANDALONE_WIN || UNITY_EDITOR || UNITY_WEBGL
            if (Input.GetMouseButton(0))
            {
                return new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"));
            }
            else
            {
                return Vector2.zero;
            }
#elif UNITY_ANDROID
            if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Moved )
            {
                return Input.GetTouch(0).deltaPosition * 0.02f; // 调整灵敏度
            }
            else
            {            
                return Vector2.zero;
            }
#endif
        }

        /// <summary>
        /// 获取缩放输入
        /// </summary>
        float GetZoomInput()
        {
#if UNITY_STANDALONE_WIN || UNITY_EDITOR || UNITY_WEBGL
            return Input.GetAxis("Mouse ScrollWheel");
#elif UNITY_ANDROID
        if (Input.touchCount == 2)
        {
            Touch touch1 = Input.GetTouch(0);
            Touch touch2 = Input.GetTouch(1);
        
            Vector2 prevPos1 = touch1.position - touch1.deltaPosition;
            Vector2 prevPos2 = touch2.position - touch2.deltaPosition;
        
            float prevDistance = Vector2.Distance(prevPos1, prevPos2);
            float currentDistance = Vector2.Distance(touch1.position, touch2.position);
        
            return (currentDistance - prevDistance) * 0.01f;
        }
        return 0;
#endif
        }

        /// <summary>
        /// 应用公共的旋转逻辑
        /// </summary>
        void ApplyCommonRotation(Transform target_TF)
        {
            transform.RotateAround(target_TF.position, Vector3.up, moveTargetValue.x * MoveSpeed);

            if (transform.localEulerAngles.x > MaxAngle || Vector3.Dot(transform.up, Vector3.up) < 0)
            {
                moveTargetValue.y = moveTargetValue.y < 0 ? 0 : moveTargetValue.y;
            }

            if (transform.localEulerAngles.x < MinAngle)
            {
                moveTargetValue.y = moveTargetValue.y > 0 ? 0 : moveTargetValue.y;
            }

            transform.RotateAround(target_TF.position, transform.right, -moveTargetValue.y * MoveSpeed * 0.5f);
        }
    }
}